package cn.tedu.storage.tcc;

import cn.tedu.common.tcc.ResultHolder;
import cn.tedu.storage.entity.Storage;
import cn.tedu.storage.mapper.StorageMapper;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class StorageTccActionImpl implements StorageTccAction {
        @Autowired
        private StorageMapper storageMapper;

    //1.一阶段失败，没有标记，回滚不执行
    //2.一阶段成功，有成功标记，其他模块执行失败，可以执行回滚，回滚完成删除标记
        @Transactional
        @Override
        public boolean prepare(BusinessActionContext ctx, Long productId, Integer count) {
            Storage storage = storageMapper.findByProductId(productId);

            if (storage.getResidue()<count)throw new RuntimeException("库存不足");

            storageMapper.updateResidueToFrozen(productId, count);
            //true表示操作成功，反之操作失败
            /*第一阶段成功时，设置成功标记 Action类--事务id--“p”
             * 添加此标记做幂等性控制
             * */
            ResultHolder.setResult(StorageTccAction.class, ctx.getXid(), "p");
            return true;
        }
        @Transactional
        @Override
        /*加synchronized避免多个线程同时提交造成数据出错*/
        public synchronized boolean commit(BusinessActionContext ctx) {
            /*二阶段执行前先检查标记是否存在，若存在，执行第二步，若不存在，则不执行*/
            if (ResultHolder.getResult(StorageTccAction.class, ctx.getXid() ) == null) {
                return true;
            }
            Long productId = Long.valueOf(ctx.getActionContext("productId").toString());
            Integer count = Integer.valueOf(ctx.getActionContext("count").toString());
            storageMapper.updateFrozenToUsed(productId,count);
            /*二阶段完成后删除标记，防止重复执行此操作*/
            ResultHolder.removeResult(StorageTccAction.class, ctx.getXid());
            return true;
        }
        @Transactional
        @Override
        public synchronized boolean rollback(BusinessActionContext ctx) {
            /*rollback阶段执行前先检查标记是否存在，若存在，执行rollback，若不存在，则不执行*/
            //一阶段失败，没有标记，回滚不执行
            if (ResultHolder.getResult(StorageTccAction.class, ctx.getXid() ) == null) {
                return true;
            }
            Long productId = Long.valueOf(ctx.getActionContext("productId").toString());
            Integer count = Integer.valueOf(ctx.getActionContext("count").toString());
            storageMapper.updateFrozenToResidue(productId,count);
            /*rollback执行完成后删除标记，防止重复执行此操作*/
            ResultHolder.removeResult(StorageTccAction.class, ctx.getXid());
            return true;
        }
}
